{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "# クラスメソッド\n",
    "\n",
    "* クラスメソッド\n",
    "    * クラスオブジェクトをレシーバとするメソッド\n",
    "        * newメソッドなど\n",
    "    * クラスに対する特異クラスのメソッドとして定義する"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## クラスのレイヤと継承チェーン\n",
    "\n",
    "<img src=\"img/4-18_19.png\" alt=\"ニューラルネットワークの例\" title=\"ニューラルネットワークの例\"/>  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "レイヤと継承チェーンの図に従ってfoo1インスタンスから別経路でObjectクラスを表示\n",
      "Object\n",
      "Object\n"
     ]
    }
   ],
   "source": [
    "class Foo\n",
    "end\n",
    "\n",
    "foo1 = Foo.new\n",
    "\n",
    "puts \"レイヤと継承チェーンの図に従ってfoo1インスタンスから別経路でObjectクラスを表示\"\n",
    "puts foo1.class.class.superclass.superclass\n",
    "puts foo1.class.superclass"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## Classクラス\n",
    "\n",
    "* Classクラス\n",
    "    * クラスを定義するクラス\n",
    "    * クラスはClassクラスのインスタンス\n",
    "        * Classクラスのインスタンスの生成 = クラスを定義\n",
    "* クラスオブジェクト\n",
    "    * Classクラスのオブジェクト\n",
    "        * 今までのFooとかHogeとか"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "foo1インスタンスのクラスはFooクラス\n",
      "Foo\n",
      "FooクラスオブジェクトのクラスはClassクラス\n",
      "Class\n",
      "Module\n"
     ]
    }
   ],
   "source": [
    "class Foo\n",
    "  def method1\n",
    "  end\n",
    "end\n",
    "foo1 = Foo.new\n",
    "\n",
    "puts \"foo1インスタンスのクラスはFooクラス\"\n",
    "puts foo1.class\n",
    "puts \"FooクラスオブジェクトのクラスはClassクラス\"\n",
    "puts Foo.class"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Classクラスによるクラスの定義\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "(pry):24: warning: already initialized constant SomeClass\n",
      "(pry):21: warning: previous definition of SomeClass was here\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "SomeClass"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "puts \"Classクラスによるクラスの定義\"\n",
    "SomeClass = Class.new"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## スーパークラスとメソッドの定義\n",
    "\n",
    "* スーパークラス\n",
    "    * newメソッドの引数で指定\n",
    "* メソッドの定義\n",
    "    * ブロックで指定"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "(pry):154: warning: already initialized constant FooExt\n",
      "(pry):132: warning: previous definition of FooExt was here\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "FooExtクラスの継承クラスとインスタンスメソッド\n",
      "[FooExt, Foo, Object, PP::ObjectMixin, JSON::Ext::Generator::GeneratorMethods::Object, Kernel, BasicObject]\n",
      "[:method2]\n",
      "Fooクラスの継承クラスとインスタンスメソッド\n",
      "[Foo, Object, PP::ObjectMixin, JSON::Ext::Generator::GeneratorMethods::Object, Kernel, BasicObject]\n",
      "[]\n"
     ]
    }
   ],
   "source": [
    "FooExt = Class.new(Foo) do\n",
    "  def initialize(a, b)\n",
    "    @b = b\n",
    "    super(a)\n",
    "  end\n",
    "  \n",
    "  def method2(c)\n",
    "    @a + @b + c\n",
    "  end\n",
    "end\n",
    "\n",
    "puts \"FooExtクラスの継承クラスとインスタンスメソッド\"\n",
    "puts FooExt.ancestors\n",
    "puts FooExt.instance_methods(false)\n",
    "\n",
    "puts \"Fooクラスの継承クラスとインスタンスメソッド\"\n",
    "puts Foo.ancestors\n",
    "puts Foo.instance_methods(false)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## Moduleクラスのインスタンス\n",
    "\n",
    "* Moduleクラスのインスタンスがモジュール\n",
    "    * Classクラスのインスタンスがクラスであるのと同様\n",
    "* ClassクラスのスーパークラスはModuleクラス"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[Class, Module, Object, PP::ObjectMixin, JSON::Ext::Generator::GeneratorMethods::Object, Kernel, BasicObject]\n",
      "[Module, Object, PP::ObjectMixin, JSON::Ext::Generator::GeneratorMethods::Object, Kernel, BasicObject]\n",
      "Module\n"
     ]
    }
   ],
   "source": [
    "puts Class.ancestors\n",
    "puts Module.ancestors\n",
    "puts Class.superclass"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## クラスメソッドの定義\n",
    "\n",
    "* Classクラスにメソッドを定義するとクラスメソッドになる\n",
    "    * 全てのクラスに対してメソッドが有効になる"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "クラスメソッドの表示\n",
      "[:constants, :nesting, :new, :allocate, :superclass, :json_creatable?, :c_method1, :<=>, :module_exec, :class_exec, :<=, :>=, :==, :===, :include?, :included_modules, :ancestors, :name, :public_instance_methods, :instance_methods, :private_instance_methods, :protected_instance_methods, :const_get, :const_defined?, :const_set, :class_variables, :class_variable_get, :remove_class_variable, :class_variable_defined?, :class_variable_set, :private_constant, :public_constant, :singleton_class?, :deprecate_constant, :freeze, :inspect, :module_eval, :const_missing, :prepend, :method_defined?, :class_eval, :public_method_defined?, :private_method_defined?, :<, :public_class_method, :>, :pretty_print, :protected_method_defined?, :pretty_print_cycle, :private_class_method, :to_s, :autoload, :autoload?, :instance_method, :public_instance_method, :include, :pry, :__binding__, :pretty_print_instance_variables, :pretty_print_inspect, :to_json, :instance_of?, :public_send, :instance_variable_get, :instance_variable_set, :instance_variable_defined?, :remove_instance_variable, :private_methods, :kind_of?, :instance_variables, :tap, :public_method, :singleton_method, :is_a?, :extend, :define_singleton_method, :method, :to_enum, :enum_for, :=~, :!~, :eql?, :respond_to?, :display, :object_id, :send, :gem, :pretty_inspect, :nil?, :hash, :class, :singleton_class, :clone, :dup, :itself, :taint, :tainted?, :untaint, :untrust, :trust, :untrusted?, :methods, :protected_methods, :frozen?, :public_methods, :singleton_methods, :!, :!=, :__send__, :equal?, :instance_eval, :instance_exec, :__id__]\n",
      "Moduleクラスのメソッドの表示\n",
      "[:constants, :nesting]\n",
      "1\n",
      "1\n"
     ]
    }
   ],
   "source": [
    "### クラスメソッドの追加\n",
    "class Class\n",
    "  def c_method1\n",
    "    1\n",
    "  end\n",
    "end\n",
    "\n",
    "puts \"クラスメソッドの表示\"\n",
    "puts Class.methods\n",
    "\n",
    "puts \"Moduleクラスのメソッドの表示\"\n",
    "puts Module.methods(false)\n",
    "\n",
    "puts String.c_method1\n",
    "puts BasicObject.c_method1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## 一つのクラスのみにクラスメソッドを追加する場合\n",
    "  \n",
    "* 特異クラスのメソッド定義やオープン式にクラスオブジェクトを指定"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "2\n",
      "3\n",
      "4\n",
      "5\n"
     ]
    }
   ],
   "source": [
    "### def式でクラスオブジェクトを指定する\n",
    "class Foo\n",
    "  def Foo.c_method2; 2; end\n",
    "end\n",
    "puts Foo.c_method2\n",
    "\n",
    "### selfはクラス自身(Foo2)を指す書き方\n",
    "class Foo2\n",
    "  def self.c_method3; 3; end\n",
    "end\n",
    "puts Foo2.c_method3\n",
    "\n",
    "### 特異クラスの再オープンを利用した書き方\n",
    "### selfの指定が一度だけなのでたくさんクラスメソッドを定義する場合に向いている\n",
    "class Foo3\n",
    "  class << self\n",
    "    def c_method4; 4; end\n",
    "    def c_method5; 5; end\n",
    "  end\n",
    "end\n",
    "puts Foo3.c_method4\n",
    "puts Foo3.c_method5"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Ruby 2.3.1",
   "language": "ruby",
   "name": "ruby"
  },
  "language_info": {
   "file_extension": ".rb",
   "mimetype": "application/x-ruby",
   "name": "ruby",
   "version": "2.3.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
